package robber.impl;

import configuration.RobConfiguration;
import http.util.HtmlUtil;
import http.util.ParseUtil;
import main.robClass;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import robber.AbstractRobber;
import timer.saveCookieManager;
import timer.saveCoursesManager;
import timer.saveRobberManager;
import user.IUser;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

import static http.BasicRequest.defaultHeader;

public class PERobber extends AbstractRobber {

    /**体育课需要记载课程id 以及 课程id对应的VIEWSTATE 一起发包才行*/
    /**@param String 课程名字*/
    /**@param ArrayList 课程名以及*/
    /***/
    /**
     * 能够通过访问课程id后获取 此课程id的viewstate 课程隐藏id 列表
     */


    /**
     * 定时抢课任务
     * 抢课线程开启后 会执行定时抢课任务  -> 这里是实现多线程的关键 在高层那边执行的都是同一个实例的Thread start
     * 定时抢课任务负责遍历用户课程 执行抢课方法 进行抢课
     **/
    @Deprecated
    Timer peRobTimer = new Timer();

    private HashMap<String, ArrayList<ArrayList<String>>> idToViewStateAndListBoxAndCookieCache = new HashMap<>();

    public PERobber(IUser user) {

        super(user);
    }


    public HashMap<String, ArrayList<ArrayList<String>>> getIdToViewStateAndListBoxAndCookieCache() {
//        robClass.logger.info("idToViewStateAndListBoxAndCookieCache:" + idToViewStateAndListBoxAndCookieCache);
        return idToViewStateAndListBoxAndCookieCache;
    }

    public void setIdToViewStateAndListBoxAndCookieCache(HashMap<String, ArrayList<ArrayList<String>>> idToViewStateAndListBoxAndCookieCache) {
        this.idToViewStateAndListBoxAndCookieCache = idToViewStateAndListBoxAndCookieCache;
    }
    /**考虑容量与效率 我应该选用LRU淘汰才对 需要优化 到时候git push后进行优化*/
    /**
     * 要求导入:
     * FirstViewState
     * idToViewStateAndListBoxAndCookieCache - viewState ListBox2 Cookie
     * 同时 应该开启备份线程 10秒后进行第一次备份
     **/


    /***
     * 根据搜索课程后的viewstate来获取抢课需要的参数:must3Params
     * 必备三大参数搜索前置参数 从异步课程搜索获取 firstViewState 作为参数进行发包
     * @variable viewstate
     * @variable listBox2
     * @variable cookie
     * 注意 这三者要一起发包才算作抢课有效
     */
    public void initPreRob(String courseId) {
        try {

            //todo 移交给上一层处理
            ///**查看是否有从search_classes获取的firstViewState*/
            String randomCookie = getUser().getRandomCookie();
            String randomViewState = super.getRandomFirstViewState();
            if (StringUtils.isBlank(randomCookie) || StringUtils.isBlank(randomViewState)) {
            robClass.logger.info("找不到资源初始化前置的randomViewState||randomCookie");
            return;
            }
            /**发包参数*/
            String url = RobConfiguration.URL + "/xstyk.aspx?xh=" + super.getUser().getUsername() + "&xm=" +
                    URLEncoder.encode(super.getUser().getStudentName(), "gb2312") +
                    "&gnmkdm=N121205";

            String bodyContent = "__EVENTTARGET=ListBox1&__EVENTARGUMENT=&__VIEWSTATE=" + URLEncoder.encode(randomViewState, "gb2312") + "&DropDownList1=%CF%EE%C4%BF&ListBox1=" + courseId;

            Request request = getBasicRequest().getBasicRequest().newBuilder()
                    .url((url))
                    .header("cookie", randomCookie)
                    .post(RequestBody.create(MediaType.parse(defaultHeader), bodyContent))
                    .build();

            Call call = getBasicRequest().getDefaultHttpClient().newCall(request);

            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    robClass.logger.info("initPreRob  || 访问网页失败");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String listBox2;
                    ArrayList<String> listBox2AndViewStateAndCookie = new ArrayList<>();
                    String responseHtml = response.body().string();
                    response.close();
                    Document doc = Jsoup.parse(responseHtml);
                    Element listBox2Element = doc.body().select("select[name=ListBox2]").select("option").first();
                    String viewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);

                    /**获取选项框*/
                    if (listBox2Element == null) {
                        robClass.logger.info(getUser().getUsername()+"找不到选项框");
                        //System.out.println(responseHtml);
                        return;
                    }

                    /**联网后发包就看这三个参数 其他不用多管*/
//                    robClass.logger.info(getIdToViewStateAndListBoxAndCookieCache());
//                    if (getIdToViewStateAndListBoxAndCookieCache().isEmpty()) {
                    listBox2 = listBox2Element.val();
                    listBox2AndViewStateAndCookie.add(viewState);
                    listBox2AndViewStateAndCookie.add(listBox2);
                    listBox2AndViewStateAndCookie.add(randomCookie);

                    /**将获取到的内容写入缓存区*/
                    //robIdAndCourseNameCache.put(courseId, listBox2AndViewStateAndCookie);
                    if (!getIdToViewStateAndListBoxAndCookieCache().containsKey(courseId)) {
                        getIdToViewStateAndListBoxAndCookieCache().put(courseId, new ArrayList<>());
                    }
                    /**考虑淘汰算法 因为永无止境的数据会撑爆mysql支持的类型限制长度/容量*/
                    /**ArrayList<String>存放的是must3Params
                     * 这是一个存放must3Params的数组*/
                    ArrayList<ArrayList<String>> viewStateAndListBoxAndCookieList = getIdToViewStateAndListBoxAndCookieCache().get(courseId);

                    /**保证数量不超过抢课线程量的两倍*/
                    if (viewStateAndListBoxAndCookieList.size() > RobConfiguration.ROB_COURSE_NUM * 2) {
                        viewStateAndListBoxAndCookieList.remove(0);
                    }
                    getIdToViewStateAndListBoxAndCookieCache().get(courseId).add(listBox2AndViewStateAndCookie);
//                        robClass.logger.info("listBox2AndViewStateAndCookie:" + listBox2AndViewStateAndCookie);
//                  }

                    /**序列化进数据库
                     * 保证程序崩溃重启立刻进行抢课
                     * 不需再做前置操作*/
                    saveCookieManager.updateUserToGlobalIdAndCookies(PERobber.this.getUser());
                    saveRobberManager.updateUserToGlobalIdAndRobberInfo(PERobber.this);
                }
            });

        } catch (NullPointerException e) {
            robClass.logger.info("initPreRob - Null");
            e.printStackTrace();

        } catch (Exception e) {
            robClass.logger.info("initPreRob - Unknown");
            e.printStackTrace();
        }
    }


    /**
     * 同步读课程线程
     * 用来人工录入抢课信息时候用
     */
    @Override
    protected HashMap<String, String> sync_search_Classes() {

        Response response = null;
        String responseHtml = null;
        HashMap<String,String> tempCourseList = new HashMap<>();
        try {
            response = getBasicRequest().sync_getWithRandomCookie(
                    "/xstyk.aspx?xh=" + super.getUser().getUsername() + "&xm=" + URLEncoder.encode(super.getUser().getStudentName(), "gb2312")
                            + "&gnmkdm=N121205", this.getUser());
            if (response == null){
                robClass.logger.info("搜索课程失败 可能随机random");
                return null;
            }
            responseHtml = response.body().string();
            //robClass.logger.info(responseHtml);
            response.close();
            HtmlUtil.parsePESelectCourseList(responseHtml, super.getIdAndCourseNameCache());
            HtmlUtil.parsePESelectCourseList(responseHtml,  tempCourseList);
            robClass.logger.info("资源初始化后的课表数据: " + super.getIdAndCourseNameCache());
            String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
            super.getFirstViewState().add(firstViewState);
        } catch (Exception e) {
            robClass.logger.info("同步搜索过程出现异常,使用缓存课表#" + saveCoursesManager.getGlobalIdAndCourseNameCache().size());
            return saveCoursesManager.getGlobalIdAndCourseNameCache();
        }
        if (super.getIdAndCourseNameCache() == null || super.getIdAndCourseNameCache().isEmpty()) {
            return saveCoursesManager.getGlobalIdAndCourseNameCache();
        }
        return tempCourseList;
    }

    /**
     * 异步获取课程表
     * 同时获取firstViewState -> 决定了体育课三大必备参数 must3Params
     * 后续发包有must3Params直接发抢课包就行
     */
    @Override
    protected void async_search_Classes() {
        try {
            Call call = getBasicRequest().async_getWithRandomCookie("/xstyk.aspx?xh=" + super.getUser().getUsername() + "&xm=" + URLEncoder.encode(super.getUser().getStudentName(), "gb2312")
                    + "&gnmkdm=N121205", this.getUser());
            if (call == null) {
                return;
            }
            call.enqueue(new Callback() {
                public void onFailure(Call call, IOException e) {
                    robClass.logger.info("异步-获取课表失败: 网络请求超时");
                    if (PERobber.super.getIdAndCourseNameCache().isEmpty()) {
                        robClass.logger.info("异步-获取课表失败, 由于用户课表为空, 使用缓存课表#" + saveCoursesManager.getGlobalIdAndCourseNameCache().size());
                        PERobber.super.setIdAndCourseNameCache(saveCoursesManager.getGlobalIdAndCourseNameCache());
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String responseHtml = response.body().string();
                    response.close();
                    HtmlUtil.parsePESelectCourseList(responseHtml, PERobber.super.getIdAndCourseNameCache());
                    String firstViewState = HtmlUtil.getViewStateFromResponseHtml(responseHtml);
                    PERobber.super.getFirstViewState().add(firstViewState);
                    /**获取FirstViewState后进行序列化备份*/
                    saveCookieManager.updateUserToGlobalIdAndCookies(PERobber.super.getUser());
                    saveRobberManager.updateUserToGlobalIdAndRobberInfo(PERobber.this);
                }
            });
        } catch (Exception e) {
            robClass.logger.info(getUser().getUsername() + "#搜索课程失败");
            //e.printStackTrace();
        }
    }




    /**
     * 抢体育课功能 - 正常模式
     *
     * @param classId 获取到must3Params 直接发包抢课
     **/

    public void rob(String classId,boolean isCrazyMode) {
        /**课程名：课程ID 缓存*/

        if (getIdToViewStateAndListBoxAndCookieCache() == null || getIdToViewStateAndListBoxAndCookieCache().isEmpty() || !getIdToViewStateAndListBoxAndCookieCache().containsKey(classId)) {
            //robClass.logger.info("找不到能抢课的参数: ViewState ListBox2 Cookie");
            return;
        }
        Random random = new Random();
        ArrayList<ArrayList<String>> ListBox2AndViewStateList = getIdToViewStateAndListBoxAndCookieCache().get(classId);
        if (ListBox2AndViewStateList.size() <= 0) {
            return;
        }

        int randomInt = random.nextInt(ListBox2AndViewStateList.size());
        ArrayList<String> listBox2AndViewState = ListBox2AndViewStateList.get(randomInt);
//        ArrayList<String> listBox2AndViewState = ListBox2AndViewStateList.get(0);
        //robClass.logger.info("随机获取支持抢课的参数 - random - ViewState ListBox2 Cookie:" + listBox2AndViewState);
        if (listBox2AndViewState == null) {
            return;
        }

        String viewState = listBox2AndViewState.get(0);
        String listBox2 = listBox2AndViewState.get(1);
        String cookie = listBox2AndViewState.get(2);

        try {
            String bodyContent = "__EVENTTARGET=&__EVENTARGUMENT=" + "&DropDownList1=%CF%EE%C4%BF&ListBox1=" + classId + "&ListBox2=" + URLEncoder.encode(listBox2, "gb2312") + "&RadioButtonList1=0&button3=%D1%A1%B6%A8%BF%CE%B3%CC";

            String uri = "/xstyk.aspx?xh=" + super.getUser().getUsername() + "&xm=" +
                    URLEncoder.encode(super.getUser().getStudentName(), "gb2312") +
                    "&gnmkdm=N121205";

            Call call;

            if (RobConfiguration.isCrazyRobMode&&isCrazyMode) {
                call = super.getBasicRequest().crazy_pe_postWithCookieAndViewState(uri,
                        bodyContent,
                        cookie,
                        URLEncoder.encode(viewState, "gb2312"));
            } else {
                call = super.getBasicRequest().pe_postWithCookieAndViewState(uri,
                        bodyContent,
                        cookie,
                        URLEncoder.encode(viewState, "gb2312"));
            }

            final IUser user = super.getUser();
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    if (!RobConfiguration.isCrazyRobMode) {
                        robClass.logger.info(new Date() + "#" + getUser().getUsername() + " #3异步-抢课失败: 网络请求超时");
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        if (getIdAndCourseNameCache().isEmpty()) {
                            PERobber.this.setIdAndCourseNameCache(saveCoursesManager.getGlobalIdAndCourseNameCache());
                            robClass.logger.info("用户没有课表,目前从缓存中获取课表" + getIdAndCourseNameCache().size() + "#" + getIdAndCourseNameCache().toString());
                        }
                        String responseHtml = response.body().string();
                        response.close();
                        String courseName = classId;

                        if (getIdAndCourseNameCache().containsKey(classId)) {
                            courseName = getIdAndCourseNameCache().get(courseName);
                        }

                        String result = ParseUtil.parsePERobScript(responseHtml);
                        if (result == null) {
                            robClass.logger.info("检测抢课状态失败");
                        }
                        robClass.logger.info(new Date() + "#" + user.getUsername() + "#" + user.getStudentName() + "#课程名:" + courseName + "#抢课状态:" + result);
                    } catch (Exception e) {
                        e.printStackTrace();
                        robClass.logger.info("classId" + classId);
                        robClass.logger.info("IdAndCourseNameCache:" + getIdAndCourseNameCache().size());
                        robClass.logger.info("IdAndCourseNameCache:" + getIdAndCourseNameCache());
                        robClass.logger.info("找不到课程名字对应的内容");
                    }
                }
            });
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }


    /**
     * 停止抢课线程
     * stop()会让数据有概率不安全
     * 因此使用interrupt()
     **/
    @Override
    protected void stop_rob() {
        /**要不直接关程序算了吧…… 开了还关抢个寂寞....*/
    }

    @Override
    protected void setTimer_rob() {

    }

    @Override
    public String toString() {
        return "PERobber{" +
                "idToViewStateAndListBoxAndCookieCache=" + idToViewStateAndListBoxAndCookieCache +
                "} " + super.toString();
    }
}
